/*
Copyright (C) 2013 Bengt Martensson.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see http://www.gnu.org/licenses/.
*/

package org.harctoolbox.guicomponents;

import java.awt.Window;
import javax.swing.ButtonGroup;
import javax.swing.JMenu;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

/**
 * This class allows for manipulation of the Look and feel of a Window.
 */
public class LookAndFeelManager {
    private final String[] lafNames;
    private final UIManager.LookAndFeelInfo[] lafInfo;
    private JRadioButton[] lafRadioButtons = null;
    private ButtonGroup lafButtonGroup = null;
    private final Window topLevel;
    private int currentIndex;
    private final ILookAndFeelManagerCaller caller;

    /**
     * Allows for error reporting function and a set-property function of the caller.
     */
    public interface ILookAndFeelManagerCaller {
        /**
         * Used for error reporting through the caller.
         * @param ex Exception.
         * @param str Error message.
         */
        void err(Exception ex, String str);

        /**
         * Sets a property of the caller, or something similar.
         * @param index System dependent index of the LAF class.
         */
        void setLAFProperty(int index);
    }

    /**
     * Allows for setting Look and feel.
     *
     * @param topLevel Window to be manipulated.
     * @param lafMenu Submenu to be filled. Must be generated by the caller, or null.
     * @param caller ILookAndFeelManager representing the caller.
     */
    public LookAndFeelManager(Window topLevel, JMenu lafMenu, ILookAndFeelManagerCaller caller) {
        this.caller = caller;
        this.topLevel = topLevel;
        lafInfo = UIManager.getInstalledLookAndFeels();
        lafNames = new String[lafInfo.length];
        if (lafMenu != null) {
            lafButtonGroup = new ButtonGroup();
            lafRadioButtons = new JRadioButton[lafInfo.length];
        }
        for (int i = 0; i < lafInfo.length; i++) {
            lafNames[i] = lafInfo[i].getName();
            if (lafMenu != null) {
                JRadioButton menuItem = new JRadioButton(lafNames[i]);
                lafRadioButtons[i] = menuItem;
                final int lafIndex = i;
                menuItem.addActionListener(new java.awt.event.ActionListener() {
                    @Override
                    public void actionPerformed(java.awt.event.ActionEvent evt) {
                        setLAF(lafIndex);
                        updateLAF();
                    }
                });

                lafButtonGroup.add(menuItem);
                lafMenu.add(menuItem);
            }
        }
    }

    /**
     * Sets the Look and feel. Does not update the window. Calls the caller's err-function if error occurs.
     *
     * @param index System dependent index of LAF.
     */
    public void setLAF(int index) {
        try {
            setLAFex(index);
        } catch (ClassNotFoundException ex) {
            caller.err(ex, "Class not found");
        } catch (InstantiationException ex) {
            caller.err(ex, null);
        } catch (IllegalAccessException ex) {
            caller.err(ex, null);
        } catch (UnsupportedLookAndFeelException ex) {
            caller.err(ex, "Unsupported LAF");
        }
    }

    /**
     * Sets the Look and feel. Does not update the window. Does not call the caller's err-function if error occurs.
     * @param index System dependent index of LAF.
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws UnsupportedLookAndFeelException
     */
    public void setLAFex(int index) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException {
        UIManager.setLookAndFeel(lafInfo[index].getClassName());
        if (lafRadioButtons != null)
            for (int i = 0; i < lafInfo.length; i++)
                lafRadioButtons[i].setSelected(i == index);
        caller.setLAFProperty(index);
        currentIndex = index;
    }

    /**
     * Updates the window for a possibly newly selected LAF.
     */
    public void updateLAF() {
        SwingUtilities.updateComponentTreeUI(topLevel);
        topLevel.pack();
    }

    /**
     * Returns class name of currently selected LAF.
     * @return Class name of currently selected LAF.
     */
    public String getCurrentLAFClassName() {
        return lafInfo[currentIndex].getClassName();
    }
}
